/**
  * @file       stack.c
  * @author     const_zpc (any question please send mail to const_zpc@163.com)
  * @brief      该文件提供单向栈LIFO功能
  * @version    0.1
  * @date       2023-03-26
  * 
  * 
  * ********************************************************************************************************************
  * @details    功能列表说明：
  *             + 迭代器
  *             + 元素访问
  * 
  * ********************************************************************************************************************
  * @par 源码路径: https://gitee.com/const-zpc/cot.git 具体问题及建议可在该网址填写 Issue
  * @par 修改日志:
  * <table>
  * <tr><th>Date           <th>Version   <th>Author      <th>Description
  * <tr><td>2023-03-26     <td>1.0       <td>const_zpc       <td>初版
  * </table>
  * ********************************************************************************************************************
  */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "container/stack.h"
#include <string.h>

/**
  * @brief      栈初始化
  * 
  * @note       会根据buf大小和元素的大小限制自动计算得到栈的限制数目
  * @param      pStack 栈句柄
  * @param      pBuf   栈预留BUF
  * @param      bufSize 栈预留BUF大小
  * @param      itemSize 栈元素大小限制
  */
void cotStack_Init(cotStack_t *pStack, uint8_t *pBuf, size_t bufSize, size_t itemSize)
{
    pStack->pBuf = pBuf;
    pStack->itemSize = itemSize;
    pStack->limit = bufSize / itemSize;
    pStack->idx = 0;
}

/**
  * @brief      判断栈是否为空
  * 
  * @param      pStack 栈句柄
  * @return     true   空
  * @return     false  非空
  */
bool cotStack_Empty(cotStack_t *pStack)
{
    return pStack->idx == 0 ? true : false;
}

/**
  * @brief      判断栈是否满了
  * 
  * @param      pStack 栈句柄
  * @return     true  已满
  * @return     false 未满
  */
bool cotStack_Full(cotStack_t *pStack)
{
    if (pStack->idx < pStack->limit)
    {
        return false;
    }

    return true;
}

/**
  * @brief      获取栈元素数目
  * 
  * @param      pStack 栈句柄
  * @return     元素数目 
  */
size_t cotStack_Size(cotStack_t *pStack)
{
    return pStack->idx;
}

/**
  * @brief      返回栈顶端元素数据指针
  * 
  * @param      pStack 栈句柄
  * @return     顶端元素数据指针
  */
void *cotStack_Top(cotStack_t *pStack)
{
    if (pStack->idx > 0)
    {
        return &pStack->pBuf[pStack->itemSize * (pStack->idx - 1)];
    }
    
    return NULL;
}

/**
  * @brief      往栈顶端推送新的元素数据
  * 
  * @param      pStack  栈句柄
  * @param      pdata   数据内容
  * @param      length  数据长度, 小于等于初始化设置的元素大小
  * @return     int 
  */
int cotStack_Push(cotStack_t *pStack, const void *pdata, size_t length)
{
    if (length > pStack->itemSize)
    {
        return -1;
    }
    
    if (pStack->idx >= pStack->limit)
    {
        return -1;
    }
    
    memcpy(&pStack->pBuf[pStack->itemSize * pStack->idx], pdata, length < pStack->itemSize ? length : pStack->itemSize);
    pStack->idx++;
    return 0;
}

/**
  * @brief      栈顶端弹出一个元素
  * 
  * @param      pStack 栈句柄
  * @return     0,成功; -1,失败
  */
int cotStack_Pop(cotStack_t *pStack)
{
    if (cotStack_Size(pStack) == 0)
    {
        return -1;
    }
    
    pStack->idx--;
    return 0;
}

/**
  * @brief      两个栈内存进行交换
  * 
  * @param      pStack     被交换的栈句柄
  * @param      pNewStack  交换的栈句柄
  */
void cotStack_Swap(cotStack_t *pStack, cotStack_t *pNewStack)
{
    *pNewStack = *pStack;
    cotStack_Init(pStack, pNewStack->pBuf, pNewStack->itemSize * pNewStack->limit, pNewStack->itemSize);
}
